package com.transaction.util;

import com.transaction.controller.StudentController;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanCreationException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ConfigurableApplicationContext;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

/**
 * Created with LXD
 *
 * @author:Luhui
 * @qq:729913162
 * @Date:2018-09-22
 * @Time:12:00
 */
public class SuperTransactionProcessor implements BeanFactoryPostProcessor {

    //记录每个类中的哪些方法需要被代理
    private final Map<Class<?>,Set<Method>> transactionMethodMap = new HashMap<>();

    //记录每个类被代理的原对象
    private final Map<Class<?>,Object> transactionMethodObj = new HashMap<>();

    @Autowired
    private SuperTransactionInterceptor interceptor;

    public Map<Class<?>, Set<Method>> getTransactionMethodMap() {
        return transactionMethodMap;
    }

    public Map<Class<?>, Object> getTransactionMethodObj() {
        return transactionMethodObj;
    }

    //该方法在spring容器初始化前执行
//    @Override
//    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
//    //扫描当前的bean有没有方法被SuperTransaction注解
//        if(scanTransaction(bean,beanName)){
//            //存在则生成cgLib代理类
//            System.out.println(bean.getClass().getName()+"有方法需要被代理，准备生成Cglib");
//            transactionMethodObj.put(bean.getClass(),bean);
//            bean = createCgLibProxy(bean,beanName);
//
//
//
//
//            System.out.println("成功生成cgLib");
////            beanFactory.registerSingleton(bean.getClass().getName(),bean);
//
//
//        }
//        System.out.println(beanName + "->" + bean.getClass().getName());
//        return bean;
//    }

    private boolean scanTransaction(Object bean, String beanName) {
        boolean isHaveTransactionMethod = false;
        Set<Method> allMethods = ReflectionUtils.getAllMethods(bean.getClass());
        for (Method method : allMethods) {
            if(method.isAnnotationPresent(SuperTransaction.class)){
                isHaveTransactionMethod = true;
                Set<Method> methodSet = transactionMethodMap.get(bean.getClass());
                if(methodSet == null){
                    methodSet = new HashSet<>();
                    transactionMethodMap.put(bean.getClass(),methodSet);
                }
                methodSet.add(method);


            }
        }
        return isHaveTransactionMethod;

    }

    private Object createCgLibProxy(Object bean,String beanName){
        return createCglibProxy0(bean.getClass(),beanName);
    }

    private Object createCglibProxy0(Class clazz,String beanName){
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(clazz);
        enhancer.setCallback(interceptor);
        return enhancer.create();
    }

//    @Override
//    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
//        System.out.println("after:"+beanName);
//        System.out.println("before:"+beanName);
//
//
//
//        return bean;
//    }


    private ApplicationContext applicationContext;
    private BeanDefinitionRegistry beanDefinitionRegistry;


//    @Override
//    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
//        this.applicationContext =applicationContext;
//        beanDefinitionRegistry = (BeanDefinitionRegistry) ((ConfigurableApplicationContext)applicationContext).getBeanFactory();
//    }

//    @Override
//    public void afterPropertiesSet() throws Exception {
//        StudentController bean = applicationContext.getBean(StudentController.class);
//        String name = applicationContext.getBeanNamesForType(bean.getClass())[0];
//        System.out.println(name);
//
//    }
    private Object cgLibProxy;
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        this.interceptor = beanFactory.createBean(SuperTransactionInterceptor.class);
        String[] beanDefinitionNames = beanFactory.getBeanDefinitionNames();
        for(String beanName : beanDefinitionNames){
            BeanDefinition beanDefinition = beanFactory.getBeanDefinition(beanName);
            if(StudentController.class.getName().equals(beanDefinition.getBeanClassName())){
                System.out.println("------------------------");
                Object cgLibProxy = createCglibProxy0(StudentController.class, beanName);
                beanDefinition.setBeanClassName(cgLibProxy.getClass().getName());
            }
        }

    }
}
